import 'dart:async';
import 'dart:collection';
import 'package:flutter/foundation.dart';

enum LogLevel { debug, info, warning, error }

class LogEntry {
  final DateTime time;
  final LogLevel level;
  final String message;
  final String? category; // 日志分类：connection, traffic, system, etc.

  LogEntry({
    required this.time,
    required this.level,
    required this.message,
    this.category,
  });

  Map<String, dynamic> toJson() => {
    'time': time.toIso8601String(),
    'level': level.name,
    'message': message,
    'category': category,
  };

  factory LogEntry.fromJson(Map<String, dynamic> json) {
    return LogEntry(
      time: DateTime.parse(json['time']),
      level: LogLevel.values.firstWhere((e) => e.name == json['level']),
      message: json['message'],
      category: json['category'],
    );
  }
}

class LogService extends ChangeNotifier {
  static final LogService _instance = LogService._internal();
  factory LogService() => _instance;
  LogService._internal();

  // 使用 Queue 而不是 List，性能更好
  final Queue<LogEntry> _logs = Queue<LogEntry>();
  final int _maxLogs = 1000; // 最大日志数量，防止内存溢出
  
  // 使用 StreamController 进行高效的日志流传输
  final StreamController<LogEntry> _logStreamController = 
      StreamController<LogEntry>.broadcast();
  
  Stream<LogEntry> get logStream => _logStreamController.stream;
  
  // 只返回不可修改的列表视图，避免不必要的复制
  UnmodifiableListView<LogEntry> get logs => UnmodifiableListView(_logs);
  
  int get logCount => _logs.length;

  void log(String message, {
    LogLevel level = LogLevel.info,
    String? category,
  }) {
    final entry = LogEntry(
      time: DateTime.now(),
      level: level,
      message: message,
      category: category,
    );
    
    // 添加到队列
    _logs.add(entry);
    
    // 限制日志数量，超过最大值时删除最旧的
    if (_logs.length > _maxLogs) {
      _logs.removeFirst();
    }
    
    // 通过 Stream 发送新日志，避免频繁的 notifyListeners
    _logStreamController.add(entry);
    
    // 调试模式下打印到控制台
    if (kDebugMode) {
      _printToConsole(entry);
    }
  }

  void _printToConsole(LogEntry entry) {
    final levelStr = entry.level.name.toUpperCase().padRight(7);
    final categoryStr = entry.category != null ? '[${entry.category}] ' : '';
    final timeStr = '${entry.time.hour.toString().padLeft(2, '0')}:'
                   '${entry.time.minute.toString().padLeft(2, '0')}:'
                   '${entry.time.second.toString().padLeft(2, '0')}';
    
    // 使用不同颜色区分日志级别（在支持的终端中）
    String colorCode = '';
    String resetCode = '\x1B[0m';
    
    switch (entry.level) {
      case LogLevel.debug:
        colorCode = '\x1B[35m'; // 紫色
        break;
      case LogLevel.info:
        colorCode = '\x1B[36m'; // 青色
        break;
      case LogLevel.warning:
        colorCode = '\x1B[33m'; // 黄色
        break;
      case LogLevel.error:
        colorCode = '\x1B[31m'; // 红色
        break;
    }
    
    print('$colorCode[$timeStr] $levelStr$resetCode $categoryStr${entry.message}');
  }

  // 便捷方法
  void debug(String message, {String? category}) {
    log(message, level: LogLevel.debug, category: category);
  }

  void info(String message, {String? category}) {
    log(message, level: LogLevel.info, category: category);
  }

  void warning(String message, {String? category}) {
    log(message, level: LogLevel.warning, category: category);
  }

  void error(String message, {String? category}) {
    log(message, level: LogLevel.error, category: category);
  }

  void clear() {
    _logs.clear();
    notifyListeners();
  }

  List<LogEntry> getFilteredLogs({
    LogLevel? level,
    String? category,
    DateTime? startTime,
    DateTime? endTime,
  }) {
    var filtered = _logs.where((log) {
      if (level != null && log.level != level) return false;
      if (category != null && log.category != category) return false;
      if (startTime != null && log.time.isBefore(startTime)) return false;
      if (endTime != null && log.time.isAfter(endTime)) return false;
      return true;
    });
    
    return filtered.toList();
  }

  String exportLogs({
    LogLevel? level,
    String? category,
  }) {
    final logsToExport = getFilteredLogs(level: level, category: category);
    return logsToExport.map((log) {
      final timeStr = log.time.toIso8601String();
      final levelStr = log.level.name.toUpperCase();
      final categoryStr = log.category != null ? '[${log.category}] ' : '';
      return '[$timeStr] $levelStr $categoryStr${log.message}';
    }).join('\n');
  }

  @override
  void dispose() {
    _logStreamController.close();
    super.dispose();
  }
}
